package com.luxsoft.siipap.em.replica.importadores.dbf.cxc;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.luxsoft.siipap.cxc.model.OrigenDeOperacion;
import com.luxsoft.siipap.em.replica.importadores.dbf.DBFReaderTemplate;
import com.luxsoft.siipap.model.Periodo;
import com.luxsoft.siipap.service.ServiceLocator2;
import com.luxsoft.siipap.util.DBUtils;
import com.luxsoft.siipap.util.DateUtil;
import com.luxsoft.siipap.ventas.dao.VentaDao;
import com.luxsoft.siipap.ventas.model.Venta;
import com.luxsoft.siipap.ventas.model.VentaDet;

/**
 * Permite importar salidas por ventas para un periodo desde el archivo
 * de ventas DBF en lectura directa (SIN USO DEL ODBF-JDBC BRIDGE)
 * 
 * @author Ruben Cancino
 *
 */
public class ImportadorDeVentasDBF {
	
	
	
	private Logger logger=Logger.getLogger(getClass());
	
	private DBFReaderTemplate creditoTemplate;
	private CreditoDBFMapper creditoMapper=new CreditoDBFMapper();
	
	private DBFReaderTemplate contadoTemplate;
	private ContadoDBFMapper contadoMapper=new ContadoDBFMapper();
	
	private DBFReaderTemplate ventasDetTemplate;
	
	public ImportadorDeVentasDBF(){
		creditoTemplate=new DBFReaderTemplate();
		creditoTemplate.setTabla("MOVCRE");
		
		contadoTemplate=new DBFReaderTemplate();
		
		ventasDetTemplate=new DBFReaderTemplate();
		ventasDetTemplate.setTabla("ALMACE");
		
	}
	

	public void importar(final Periodo p){
		List<Date> dias=p.getListaDeDias();
		for(Date d:dias){
			importar(d);
		}
	}
	
	public void importar(final Date dia){
		logger.info("Importando Ventas del dia:"+DateUtil.convertDateToString(dia));
		
		//Cargando partidas
		ventasDetMapper.setFecha(dia);
		ventasDet=ventasDetTemplate.query(new Periodo(dia), null, ventasDetMapper);
		logger.info("Registros de almace cargados: "+ventasDet.size());
		
		List<Venta> ventas=new ArrayList<Venta>();
		
		//Credito
		creditoMapper.setFecha(dia);
		ventas.addAll(creditoTemplate.query(new Periodo(dia), creditoMapper, creditoMapper));
		logger.info("Ventas CRE mapeadas: "+ventas.size());
		
		
		//Camioneta
		contadoTemplate.setTabla("MOCOCA");
		contadoMapper.setFecha(dia);
		contadoMapper.setOrigen(OrigenDeOperacion.CAM);
		contadoMapper.setPrefix("MCA");
		List<Venta> camioneta=contadoTemplate.query(new Periodo(dia), contadoMapper, contadoMapper);
		logger.info("Ventas CAM mapeadas: "+camioneta.size());
		ventas.addAll(camioneta);
		
		//Mostrador
		contadoTemplate.setTabla("MOCOMO");
		contadoMapper.setFecha(dia);
		contadoMapper.setOrigen(OrigenDeOperacion.MOS);
		contadoMapper.setPrefix("MCM");
		List<Venta> mostrador=contadoTemplate.query(new Periodo(dia), contadoMapper, contadoMapper);
		logger.info("Ventas MOS mapeadas: "+mostrador.size());
		ventas.addAll(mostrador);
		
		setTotal(ventas.size());
		for(Venta v:ventas){
			try {				
				v.setImportacion("DBF");
				v.setComentario2("Venta importada desde el DBF: "+DateUtil.getDate(new Date()));
				buscarPartidas(v);
				persistir(v);
				
			} catch (Exception e) {
				e.printStackTrace();
				String msg=MessageFormat.format("Cliente:{0} CXPFactura:{1} Sucursal: {2} Serie: {3} Tipo:{4} Fecha:{5,date,long} Origen:{6}"	
						,v.getClave(),v.getDocumento(),v.getSucursal(),v.getSerieSiipap(),v.getTipoSiipap(),v.getFecha(),v.getOrigen());
				System.out.println(msg);
				System.out.println(ExceptionUtils.getRootCauseMessage(e));
				
			}finally{
				updateCurrent();
			}
		}
		logger.info(" Beans mapeados: "+ventas.size());
	}
		
	protected Venta persistir(Venta fac){		
		Venta target=buscarVenta(fac.getDocumento(),fac.getSucursal().getId(),fac.getOrigen().name());
		if(target!=null){
			if(logger.isDebugEnabled()){
				logger.debug("Venta existente solo actualizando");
			}
			BeanUtils.copyProperties(fac, target,new String[]{"id","version","cliente","credito"});
			if(target.getPartidas().size()!=fac.getPartidas().size()){
				for(VentaDet det:fac.getPartidas()){
					boolean existe=fac.getPartidas().contains(det);
					if(!existe){
						logger.info("Agregando partida nueva: "+det);
						target.agregarPartida(det);
					}	
				}
			}
			target.setComentario2("Venta actualizada desde DBF:"+DateUtil.convertDateToString(new Date()));
			
			return getVentaDao().save(target);
		}else{
			return getVentaDao().save(fac);
		}		
	}
	
	public Venta buscarVenta(Long documento,Long sucursalId,String tipo){
		Object[] params=new Object[]{documento,sucursalId};
		String hql="from Venta v  " +
		"left join fetch v.partidas ap " +
		" where v.documento=? and v.sucursal.id=? and v.origen=@ORIGEN  ";
		hql=hql.replaceAll("@ORIGEN","\'"+tipo+"\'" );
		List<Venta> data=getHibernate().find(hql, params);		
		return data.isEmpty()?null:data.get(0);
	}
	
	private  List<Map<String, Object>> ventasDet=new ArrayList<Map<String, Object>>();
	
	private VentasDetDBFMapper ventasDetMapper=new VentasDetDBFMapper();
	
	private void buscarPartidas(final Venta venta){
		
		Collection<Map<String, Object>> partidas=CollectionUtils.select(ventasDet, new Predicate(){
			public boolean evaluate(Object input) {
				Map<String, Object> row=(Map<String, Object>)input;
				Integer sucursal= getSafaInt(row, "ALMSUCUR");
				Long numero=getSafaLong(row, "ALMNUMER");
				String serie=(String)row.get("ALMSERIE");
				String tipo=(String)row.get("ALMTIPFA");
				if(sucursal.equals(venta.getSucursal().getClave())){
					if(numero.equals(venta.getDocumento())){
						if(serie.equalsIgnoreCase(venta.getSerieSiipap())){
							if(tipo.equalsIgnoreCase(venta.getTipoSiipap()))
								return true;
						}
					}
				}
				return false;
			}
			
		});		
		for(Map<String,Object> row:partidas){
			try {
				VentaDet det=(VentaDet)ventasDetMapper.map(row);
				det.setTipo(venta.getTipoSiipap());
				det.setSerie(venta.getSerieSiipap());
				det.setFecha(venta.getFecha());
				
				venta.agregarPartida(det);
			} catch (Exception e) {				
				logger.error("Error mapeando ventadet: "+row,e);
				e.printStackTrace();
			}
		}
		
	}
	
	public VentaDao getVentaDao(){
		return (VentaDao)ServiceLocator2.instance().getContext().getBean("ventaDao");
	}	
	
	public double getSafaDouble(Map<String, Object> row,String key){
		Number res=(Number)row.get(key);
		return res!=null?res.doubleValue():0;
	}
	
	public long getSafaLong(Map<String, Object> row,String key){
		Number res=(Number)row.get(key);
		return res!=null?res.longValue():0;
	}
	
	public int getSafaInt(Map<String, Object> row,String key){
		Number res=(Number)row.get(key);
		return res!=null?res.intValue():0;
	}
	
	
	public HibernateTemplate getHibernate(){
		return ServiceLocator2.getHibernateTemplate();
	}
	
	
	private int current;
	
	private int total;
	
	public void setProgress(int progress){
		//System.out.println("Progress: "+progress);
	}
	
	protected void updateCurrent(){
		current++;		
		if(total!=0){
			int progress=current*100/this.total;
			//System.out.println("Progress:"+progress);
			setProgress(progress);
		}
	}
	
	public void setTotal(int total) {
		this.total = total;
		logger.info("Total de ventas a importar:"+total);
	}
	
	public static void main(String[] args) {
		DBUtils.whereWeAre();
		new ImportadorDeVentasDBF()		
		.importar(new Periodo("02/03/2009","02/03/2009"));
	}
}
